package com.sjq.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sjq.exception.CustomException;
import com.sjq.exception.CustomUnauthorizedException;
import com.sjq.mapper.NoticeMapper;
import com.sjq.mapper.PaperMapper;
import com.sjq.mapper.RoleMapper;
import com.sjq.model.common.BaseDto;
import com.sjq.model.common.BaseResult;
import com.sjq.model.common.Constant;
import com.sjq.model.common.ResponseBean;
import com.sjq.model.entity.User;
import com.sjq.model.request.*;
import com.sjq.model.response.UserResponse;
import com.sjq.model.valid.group.UserEditValidGroup;
import com.sjq.model.valid.group.UserLoginValidGroup;
import com.sjq.service.IUserService;
import com.sjq.util.AesCipherUtil;
import com.sjq.util.JedisUtil;
import com.sjq.util.JwtUtil;
import com.sjq.util.UserUtil;
import com.sjq.util.common.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.annotations.Param;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * UserController
 * @author dolyw.com
 * @date 2021/12/29 15:45
 */
@Api( tags = "用户接口")
@RestController
@RequestMapping("/user")
@PropertySource("classpath:config.properties")
public class UserController {

    /**
     * RefreshToken过期时间
     */
    @Value("${refreshTokenExpireTime}")
    private String refreshTokenExpireTime;

    private final UserUtil userUtil;

    private final IUserService userService;


    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PaperMapper paperMapper;

    @Autowired
    private NoticeMapper noticeMapper;
    @Autowired
    public UserController(UserUtil userUtil, IUserService userService) {
        this.userUtil = userUtil;
        this.userService = userService;
    }


    /**
     * 公告
     */
//    @RequiresRoles("管理员")
    @ApiOperation("发布公告")
    @GetMapping("/notice")
    public ResponseBean notice( @RequestParam String notice , @RequestParam String title) {
        return new ResponseBean(HttpStatus.OK.value(), "发布公告成功(Query was successful)", noticeMapper.updateNotice(notice,title));
    }
    @ApiOperation("获取公告")
    @GetMapping("/getNotice")
    public ResponseBean getNotice() {
        HashMap<String,String> map = new HashMap<>();
        map.put("notice" , noticeMapper.getNotice());
        map.put("title" , noticeMapper.getTitle());
        return new ResponseBean(HttpStatus.OK.value(), "获取公告成功(Query was successful)", map);
    }

        /**
         * 获取用户列表
         * @param
         */
//    @RequiresRoles("管理员"), @RequestHeader String Authorization
    @ApiOperation("获取用户列表")
    @GetMapping
    public ResponseBean user(@Validated GetUserRequest baseDto) {
        if(baseDto.getStatus()!=null){
            baseDto.setRole("专家");
            baseDto.setStatus(0L);
        }else{
            if(baseDto.getRole()!=null && baseDto.getRole().equals("专家")){
                baseDto.setStatus(1L);
            }
        }


        PageHelper.startPage(baseDto.getPageNum(), baseDto.getPageSize());
        List<UserRequest> userDto = userService.selectUser(baseDto);
        PageInfo<UserRequest> selectPage = new PageInfo<UserRequest>(userDto);
        if (userDto == null || userDto.size() < 0) {
            throw new CustomException("查询失败(Query Failure)");
        }
        Map<String, Object> result = new HashMap<String, Object>(16);
        result.put("count", selectPage.getTotal());
        result.put("data", selectPage.getList());
        return new ResponseBean(HttpStatus.OK.value(), "查询成功(Query was successful)", result);
    }

    /**
     * 获取当前登录用户信息
     * @param
     */
    @ApiOperation("获取当前登录用户信息")
    @GetMapping("/info")
    @RequiresAuthentication
    public ResponseBean info(@RequestHeader String Authorization) {

        UserResponse userResponse = new UserResponse();
        userResponse.setBasicUserInformation(userService.selectById(userUtil.getUserId().intValue()));
        userResponse.setUserRole(userService.getRoleById(userUtil.getUserId()));
        PaperRequest paperRequest = new PaperRequest()
                .setUserId(userUtil.getUserId());
        userResponse.setPaperBases(paperMapper.selectPaperList(paperRequest));
        return new ResponseBean(HttpStatus.OK.value(), "成功获取当前登录用户信息", userResponse);
    }

    /**
     * 获取指定用户
     * @param id
     */
    @RequiresAuthentication
    @ApiOperation("获取指定用户")
    @GetMapping("/{id}")
    public ResponseBean findById(@PathVariable("id") Long id, @RequestHeader String Authorization) {
        UserDto userDto = userService.selectByPrimaryKey(id);
        if (userDto == null) {
            throw new CustomException("查询失败(Query Failure)");
        }
        return new ResponseBean(HttpStatus.OK.value(), "查询成功(Query was successful)", userDto);
    }

    /**
     * 修改密码
     */
    @ApiOperation("修改密码")
    @GetMapping("/updatePassword")
    @RequiresAuthentication
//    @RequiresPermissions("user:edit")
    public ResponseBean updatePassword(@RequestParam("password") String password, @RequestHeader String Authorization) {
        // 查询数据库密码
        UserDto userDto = new UserDto();
        userDto.setPassword(password);
        userDto.setAccount(userUtil.getAccount());
        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        if (userDtoTemp == null) {
            throw new CustomUnauthorizedException("该帐号不存在(Account not exist.)");
        } else {
            userDto.setId(userDtoTemp.getId());
        }
        // FIXME: 如果不一样就说明用户修改了密码，重新加密密码(这个处理不太好，但是没有想到好的处理方式)
        if (!userDtoTemp.getPassword().equals(userDto.getPassword())) {
            // 密码以帐号+密码的形式进行AES加密
            if (userDto.getPassword().length() > Constant.PASSWORD_MAX_LEN) {
                throw new CustomException("密码最多8位(Password up to 8 bits.)");
            }
            String key = AesCipherUtil.enCrypto(userDto.getAccount() + userDto.getPassword());
            userDto.setPassword(key);
        }
        int count = userService.updateByPrimaryKeySelective(userDto);
        if (count <= 0) {
            throw new CustomException("更新失败(Update Failure)");
        }
        return new ResponseBean(HttpStatus.OK.value(), "更新成功(Update Success)", userDto);
    }


    /**
     * 更新用户
     */
    @ApiOperation("更新用户基本信息")
    @PutMapping
    @RequiresAuthentication
//    @RequiresPermissions("user:edit")
    public ResponseBean update(@Validated(UserEditValidGroup.class)@RequestBody UserDto userDto,@RequestHeader String Authorization) {
        // 查询数据库密码
        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        if (userDtoTemp == null) {
            throw new CustomUnauthorizedException("该帐号不存在(Account not exist.)");
        } else {
            userDto.setId(userDtoTemp.getId());
        }
        // FIXME: 如果不一样就说明用户修改了密码，重新加密密码(这个处理不太好，但是没有想到好的处理方式)
        if (!userDtoTemp.getPassword().equals(userDto.getPassword())) {
            // 密码以帐号+密码的形式进行AES加密
            if (userDto.getPassword().length() > Constant.PASSWORD_MAX_LEN) {
                throw new CustomException("密码最多8位(Password up to 8 bits.)");
            }
            String key = AesCipherUtil.enCrypto(userDto.getAccount() + userDto.getPassword());
            userDto.setPassword(key);
        }
        // TODO: 待编写
        int count = userService.updateByPrimaryKeySelective(userDto);
        if (count <= 0) {
            throw new CustomException("更新失败(Update Failure)");
        }
        // [XXX]: 带修正
        return new ResponseBean(HttpStatus.OK.value(), "更新成功(Update Success)", userDto);
    }

    /**
     * 删除用户（注销账户）
     * @param id
     */
    @ApiOperation("删除用户")
    @DeleteMapping("/{id}")
    @RequiresRoles(value = {"管理员"})
    public BaseResult delete(@PathVariable("id") Integer id, @RequestHeader String Authorization) {
        Long idd = id.longValue();
        int count = userService.deleteByPrimaryKey(idd);
        if (count <= 0) {
            return BaseResult.error("删除失败，ID不存在(Deletion Failed. ID does not exist.)");
        }
        return BaseResult.success("删除成功");
    }

    /**
     * 用户注册
     * @param userDto
     *
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    @ApiOperation("用户注册")
    @PostMapping("/register")
    public ResponseBean add(@RequestBody UserRequest userDto){
        // 判断当前帐号是否存在
        UserDto userDtoTemp = new UserDto();
        userDto.setAccount(userDto.getTelephoneNumber());//账号等于电话号码
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        // 检查账号名
        if (userDtoTemp != null && StringUtil.isNotBlank(userDtoTemp.getPassword())) {
            throw new CustomUnauthorizedException("该帐号已存在");
        }
        userDtoTemp = new UserDto();
        userDtoTemp.setEmail(userDto.getEmail());
        userDtoTemp = userService.selectOne(userDtoTemp);
        // 检查邮箱号
        if (userDtoTemp!= null && userDtoTemp.getStatus()!=0) {
            throw new CustomUnauthorizedException("该邮箱已被注册");
        }
        userDto.setRegTime(new Date());
        // 密码以帐号+密码的形式进行AES加密
        if (userDto.getPassword().length() > Constant.PASSWORD_MAX_LEN) {
            throw new CustomException("密码最多8位(Password up to 8 bits.)");
        }

        String key = AesCipherUtil.enCrypto(userDto.getAccount() + userDto.getPassword());
        userDto.setPassword(key);
//        String role = userDto.getRole();
        userDto.setAccount(userDto.getTelephoneNumber())
                .setAvatar("http://localhost:8888/static/people.png");

        if(userDto.isExpert()){
            userDto.setStatus(0L);}
        if(userService.insertUser(userDto)<=0){
            throw new CustomException("注册失败(Insert Failure)");
        } else{
            if(userDto.isExpert()){

                userService.insertExpertClassification(userDto.getId(),userDto.getClassificationId());
                userService.insertUserRole(userDto.getId(),2L);
            }
            if(userDto.isAuthor()){
                userService.insertUserRole(userDto.getId(),3L);
            }
            //反馈信息
            if(userDto.isExpert() && userDto.isAuthor()){
                return new ResponseBean(HttpStatus.OK.value(), "作者身份注册成功；专家身份待管理员审核，24小时内将发送审核结果到您的邮箱", userDto);
            }else if(userDto.isExpert()){
                return new ResponseBean(HttpStatus.OK.value(), "待管理员审核，24小时内将发送审核结果到您的邮箱", userDto);
            }else {
                return new ResponseBean(HttpStatus.OK.value(), "作者身份注册成功", userDto);
            }
        }


//        if(role.equals("专家")) {
//            userDto.setStatus(0L);
//            if(userService.insertUser(userDto)>0){
//                userDto.setAvatar("http://localhost:8888/static/img.png");
//                userService.insertUserRole(userDto.getId(),2L);
//                return new ResponseBean(HttpStatus.OK.value(), "待管理员审核，24小时内将发送审核结果到您的邮箱", userDto);
//            }
//            else{
//                throw new CustomException("注册失败(Insert Failure)");
//            }
//
//        }
//        else {
//            userDto.setAccount(userDto.getTelephoneNumber())
//                    .setAvatar("http://localhost:8888/static/people.png");
//            if (userService.insertUser(userDto) <= 0) {
//                throw new CustomException("注册失败(Insert Failure)");
//            }
//            userService.insertUserRole(userDto.getId(),3L);
//            return new ResponseBean(HttpStatus.OK.value(), "注册成功(Insert Success)", userDto);
//        }
    }

    /**
     * 登录授权
     * @param userDto
     * @return com.sjq.model.common.ResponseBean
     */
    @ApiOperation("用户登录授权")
    @PostMapping("/login")
    public ResponseBean login(@Validated(UserLoginValidGroup.class) @RequestBody LoginRequest userDto, HttpServletResponse httpServletResponse) {
        // 查询数据库中的帐号信息
        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        if (userDtoTemp == null) {
            throw new CustomUnauthorizedException("该帐号不存在(The account does not exist.)");
        }
        if(userDto.getFlag()==2){
            if(userDtoTemp.getStatus() == 0){
                throw new CustomUnauthorizedException("注册账号未审核,请耐心等待，注册结果会在24小时发至锁定的邮箱");
            }
            else if(userDtoTemp.getStatus() == 2) {
                throw new CustomUnauthorizedException("您注册的账号审核未通过，请重新提供确切的用户凭证信息证实您的身份，再次注册");
            }
        }
        // 密码进行AES解密
        String key = AesCipherUtil.deCrypto(userDtoTemp.getPassword());
        // 因为密码加密是以帐号+密码的形式进行加密的，所以解密后的对比是帐号+密码
        if (key.equals(userDto.getAccount() + userDto.getPassword())) {
            // 清除可能存在的Shiro权限信息缓存
            if (JedisUtil.exists(Constant.PREFIX_SHIRO_CACHE + userDto.getAccount())) {
                JedisUtil.delKey(Constant.PREFIX_SHIRO_CACHE + userDto.getAccount());
            }
            // 设置RefreshToken，时间戳为当前时间戳，直接设置即可(不用先删后设，会覆盖已有的RefreshToken)
            String currentTimeMillis = String.valueOf(System.currentTimeMillis());
            JedisUtil.setObject(Constant.PREFIX_SHIRO_REFRESH_TOKEN + userDto.getAccount(), currentTimeMillis, Integer.parseInt(refreshTokenExpireTime));
            // 从Header中Authorization返回AccessToken，时间戳为当前时间戳
            String token = JwtUtil.sign(userDto.getAccount(), currentTimeMillis);
            httpServletResponse.setHeader("Authorization", token);
            httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");
            Map<String,Object> map = new HashMap<>();
            map.put("Authorization", token);
            return new ResponseBean(HttpStatus.OK.value(), "登录成功(Login Success.)",map );
        } else {
            throw new CustomUnauthorizedException("帐号或密码错误(Account or Password Error.)");
        }
    }

    /**
     * 测试登录
     * @param
     */
//    @ApiOperation("测试登录")
//    @GetMapping("/article")
//    public ResponseBean article() {
//        Subject subject = SecurityUtils.getSubject();
//        // 登录了返回true
//        if (subject.isAuthenticated()) {
//            return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", null);
//        } else {
//            return new ResponseBean(HttpStatus.OK.value(), "你是游客(You are guest)", null);
//        }
//    }

    /**
     * 退出登陆
     * @param id
     */
    @ApiOperation("退出登陆")
    @DeleteMapping("/loginOut/{id}")
    @RequiresAuthentication
    public BaseResult deleteOnline(@PathVariable("id") Integer id, @RequestHeader String Authorization) {
        UserDto userDto = userService.selectById(id);
        if (JedisUtil.exists(Constant.PREFIX_SHIRO_REFRESH_TOKEN + userDto.getAccount())) {
            if (JedisUtil.delKey(Constant.PREFIX_SHIRO_REFRESH_TOKEN + userDto.getAccount()) > 0) {
                return BaseResult.success();
            }
        }
        return BaseResult.error();
    }

    /**
     * 审核用户
     * @return
     */
    @RequiresRoles("管理员")
    @ApiOperation("审核用户")
    @RequestMapping(value = "/updateStatus", method = RequestMethod.POST)
    public BaseResult updateStatus(@RequestBody User user, @RequestHeader String Authorization) {
        if(userService.updateStatus(user) > 0)
            return BaseResult.success();
        else
            return BaseResult.error();
    }

    /**
     * 管理员审核用户注册信息
     * @return
     */
    @RequiresRoles("管理员")
    @ApiOperation("查看需要审核的用户")
    @RequestMapping(value = "/selectUnAuthorizedUser", method = RequestMethod.POST)
    public BaseResult<List<User>> getUnAuthorizedUserList(@RequestHeader String Authorization) {
        return BaseResult.success("查询成功",userService.getUnAuthorizedUserList());
    }

}
